<?php

namespace App\Services\Traits;

use Helper\Timed;

trait DatabaseElasticsearch
{

    /**
     * 制作排序参数
     *
     * @param \Illuminate\Http\Request $request
     * @param array $params
     * @param string $column
     * @param string $order
     * @return $this
     */
    protected function makeOrderParam($request, &$params, $column = null, $order = null)
    {
        $params['body']['sort'][] = [
            $column ?: $request->input('order_column', '_id') => [
                'order' => $order ?: $request->input('order', 'desc')
            ]
        ];
        return $this;
    }

    /**
     * 制作分页参数
     *
     * @param \Illuminate\Http\Request $request
     * @param array $params
     * @return $this
     */
    protected function makePaginationParam($request, &$params)
    {
        $params['body']['from'] = ($this->getPage($request) - 1) * $this->getPageSize($request);
        $params['body']['size'] = $this->getPageSize($request);

        return $this;
    }

    /**
     * 制作查询
     *
     * @param array $params
     * @param string $column
     * @param mixed $value
     * @param string $operator
     * @return $this
     */
    protected function makeWhere(&$params, $column = null, $value = null, $operator = 'term')
    {
        $params['body']['query']['bool']['must'][] = [
            is_array($value) ? 'terms' : $operator => [
                $column => $value
            ]
        ];
        return $this;
    }

    /**
     * 制作查询【排除】
     *
     * @param array $params
     * @param string $column
     * @param mixed $value
     * @param string $operator
     * @return $this
     */
    protected function makeWhereNot(&$params, $column = null, $value = null, $operator = 'term')
    {
        $params['body']['query']['bool']['must_not'][] = [
            is_array($value) ? 'terms' : $operator => [
                $column => $value
            ]
        ];
        return $this;
    }

    /**
     * 制作查询参数
     *
     * @param \Illuminate\Http\Request $request
     * @param string $key
     * @param array $params
     * @param string $column
     * @param string $operator
     * @return $this
     */
    protected function makeWhereParam($request, $key, &$params, $column = null, $operator = 'term')
    {
        if ($this->isValidParam($request, $key)) {
            $this->makeWhere($params, $column ?: $key, $this->getParam($request, $key), $operator);
        }
        return $this;
    }

    /**
     * 制作查询参数【排除】
     *
     * @param \Illuminate\Http\Request $request
     * @param string $key
     * @param array $params
     * @param string $column
     * @param string $operator
     * @return $this
     */
    protected function makeWhereParamNot($request, $key, &$params, $column = null, $operator = 'term')
    {
        if ($this->isValidParam($request, $key)) {
            $this->makeWhereNot($params, $column ?: $key, $this->getParam($request, $key), $operator);
        }
        return $this;
    }

    /**
     * 制作查询参数【搜索】
     *
     * @param \Illuminate\Http\Request $request
     * @param array $params
     * @param string $column
     * @param string $key
     * @return $this
     */
    protected function makeWhereParamSearch($request, &$params, $column = null, $key = 'keyword')
    {
        if ($this->isValidParam($request, $key)) {

            $column = $column ?: $request->input('keyword_column', 'id');

            $this->makeWhereParam($request, $key, $params, $column);
        }
        return $this;
    }

    /**
     * 制作查询参数【datetime】
     *
     * @param \Illuminate\Http\Request $request
     * @param array $params
     * @param string $column
     * @param string $key
     * @param string|null $index
     * @return $this
     */
    protected function makeWhereParamDatetime($request, &$params, $column = null, $key = 'datetime', $index = null)
    {
        if ($this->isValidParam($request, $key)) {

            $datetime = $this->getParamArray($request, $key);

            $column = $column ?: $request->input('datetime_column', 'created');

            $params['body']['query']['bool']['must'][] = [
                'range' => [
                    $column => [
                        'gte' => $datetime[0],
                        'lte' => $datetime[1]
                    ]
                ]
            ];

            // 设置索引范围
            if (!empty($index)) {
                // 忽略不存在索引
                $params['ignore_unavailable'] = true;
                // 枚举按天分表索引（前后冗余各1天，排除时区误差）
                for ($timed = $datetime[0] - 86400; $timed <= $datetime[1] + 86400; $timed += 86400) {
                    $day = date('Y.m.d', $timed);
                    $params['index'][] = "{$index}-{$day}";
                }
            }
        }
        return $this;
    }

    /**
     * 制作查询参数【最近n天】
     *
     * @param \Illuminate\Http\Request $request
     * @param array $params
     * @param string $column
     * @param int $days
     * @return $this
     */
    protected function makeWhereLastDays($request, &$params, $column = null, $days = 30)
    {
        $request->offsetSet('datetime', [Timed::getTodayTimed() - 86400 * ($days - 1), Timed::getDayNextTimed() - 1]);

        $this->makeWhereParamDatetime($request, $params, $column, 'datetime');

        return $this;
    }

    /**
     * 制作统计参数
     *
     * @param array $params
     * @param string $column
     * @param string $agg
     * @param string $name
     * @return $this
     */
    protected function makeAgg(&$params, $column, $agg, $name = null)
    {
        $params['body']['aggs'][$name ?: $column] = [
            $agg => [
                'field' => $column
            ]
        ];
        return $this;
    }

    /**
     * 制作统计参数【多条】
     *
     * @param array $params
     * @param string $agg
     * @param array $columns
     * @return $this
     */
    protected function makeAggs(&$params, $agg, $columns)
    {
        foreach ($columns as $column) {
            $this->makeAgg($params, $column, $agg);
        }
        return $this;
    }

    /**
     * 制作统计参数【分组】【多条】
     *
     * @param array $params
     * @param string $agg
     * @param array $columns
     * @param array $groups
     * @return $this
     */
    protected function makeGroupAggs(&$params, $agg, $columns, $groups)
    {
        $params['body']['aggs']['group'] = [
            'composite' => [
                'size' => config('elasticsearch.search.max_buckets'),
                'sources' => array_map(function ($group) {
                    return is_array($group) ? $group : [$group => ['terms' => ['field' => $group]]];
                }, $groups)
            ],
            'aggs' => array_merge(...array_map(
                function ($column) use ($agg) {
                    return [
                        $column => [
                            $agg => [
                                'field' => $column
                            ]
                        ]
                    ];
                },
                $columns
            ))
        ];
        return $this;
    }

    /**
     * 制作查询参数【平台】
     *
     * @param \Illuminate\Http\Request $request
     * @param array $params
     * @param string $column
     * @return $this
     */
    protected function makeWhereOrg($request, &$params, $column = 'plat_code')
    {
        if (!$request->user()->isSuperAdmin()) {
            $this->makeWhere($params, $column, $request->user()->getTreePermissionOrgs()->pluck('code')->toArray());
        }
        return $this;
    }

    /**
     * 制作查询参数【平台】【默认值】
     *
     * @param \Illuminate\Http\Request $request
     * @param array $params
     * @param string $column
     * @param string $key
     * @return $this
     */
    protected function makeWhereParamOrg($request, &$params, $column = 'plat_code', $key = 'plat_code')
    {
        if ($this->isValidParam($request, $key)) {
            $this->makeWhere($params, $column, $this->getParam($request, $key));
        } else {
            $this->makeWhereOrg($request, $params, $column);
        }
        return $this;
    }

    /**
     * 制作查询参数【自定义字段范围筛选】
     *
     * @param \Illuminate\Http\Request $request
     * @param array $params
     * @param string $key
     * @return $this
     */
    protected function makeWhereFieldRange($request, &$params, $key = 'fieldRange')
    {
        if ($this->isValidParam($request, $key)) {
            $option = $this->getParamArray($request, $key);

            if (empty($option['field'])) {
                return $this;
            }

            if (isset($option['min']) && !is_bool($option['min']) && trim((string)$option['min']) !== '') {
                $range['gte'] = $option['min'];
            }

            if (isset($option['max']) && !is_bool($option['max']) && trim((string)$option['max']) !== '') {
                $range['lte'] = $option['max'];
            }

            if (isset($range)) {
                $params['body']['query']['bool']['must'][] = [
                    'range' => [
                        $option['field'] => $range
                    ]
                ];
            }
        }
        return $this;
    }
}
